/// @author Alexander Rykovanov 2012
/// @email rykovanov.as@gmail.com
/// @brief Test of opc ua binary handshake.
/// @license GNU LGPL
///
/// Distributed under the GNU LGPL License
/// (See accompanying file LICENSE or copy at
/// http://www.gnu.org/licenses/lgpl.html)
///

#include <opc/ua/protocol/message_identifiers.h>
#include <opc/ua/protocol/binary/stream.h>
#include <opc/ua/protocol/endpoints.h>
#include <opc/ua/protocol/types.h>

#include <algorithm>
#include <stdexcept>
#include <gtest/gtest.h>

#include "common.h"


class EndpointsSerialization : public OpcUaBinarySerialization
{
};

class EndpointsDeserialization : public OpcUaBinaryDeserialization
{
};

//-------------------------------------------------------
// GetEndpointsRequest
//-------------------------------------------------------

TEST_F(EndpointsSerialization, GetEndpointsRequest)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  GetEndpointsRequest request;

  ASSERT_EQ(request.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(request.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(request.TypeId.FourByteData.Identifier, OpcUa::GET_ENDPOINTS_REQUEST);

  FILL_TEST_REQUEST_HEADER(request.Header);
  request.Parameters.EndpointUrl = "test";
  request.Parameters.LocaleIds.push_back("RU");
  request.Parameters.ProfileUris.push_back("pro");


  GetStream() << request << flush;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xac, 0x1, // TypeId
    // RequestHeader
    TEST_REQUEST_HEADER_BINARY_DATA,
    4, 0, 0, 0, 't', 'e', 's', 't',
    1, 0, 0, 0, 2, 0, 0, 0, 'R', 'U',
    1, 0, 0, 0, 3, 0, 0, 0, 'p', 'r', 'o'
  };

  ASSERT_EQ(expectedData, GetChannel().SerializedData);
  ASSERT_EQ(expectedData.size(), RawSize(request));
}

TEST_F(EndpointsDeserialization, GetEndpointsRequest)
{
  using namespace OpcUa;
  using namespace OpcUa::Binary;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xac, 0x1, // TypeId
    // RequestHeader
    TEST_REQUEST_HEADER_BINARY_DATA,
    4, 0, 0, 0, 't', 'e', 's', 't',
    1, 0, 0, 0, 2, 0, 0, 0, 'R', 'U',
    1, 0, 0, 0, 3, 0, 0, 0, 'p', 'r', 'o'
  };

  GetChannel().SetData(expectedData);

  GetEndpointsRequest request;
  GetStream() >> request;

  ASSERT_EQ(request.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(request.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(request.TypeId.FourByteData.Identifier, OpcUa::GET_ENDPOINTS_REQUEST);

  ASSERT_REQUEST_HEADER_EQ(request.Header);

  ASSERT_EQ(request.Parameters.EndpointUrl, "test");
  ASSERT_EQ(request.Parameters.LocaleIds, std::vector<std::string>(1, "RU"));
  ASSERT_EQ(request.Parameters.ProfileUris, std::vector<std::string>(1, "pro"));
}

//----------------------------------------------------
// GetEndpointsResponse
//----------------------------------------------------

TEST_F(EndpointsSerialization, GetEndpointsResponse)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  GetEndpointsResponse response;

  ASSERT_EQ(response.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(response.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(response.TypeId.FourByteData.Identifier, OpcUa::GET_ENDPOINTS_RESPONSE);

  FILL_TEST_RESPONSE_HEADER(response.Header);

  EndpointDescription endpoint;
  FILL_TEST_ENDPOINT(endpoint);
  response.Endpoints.push_back(endpoint);

  GetStream() << response << flush;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xaf, 0x1, // TypeId
    // RequestHeader
    TEST_RESPONSE_HEADER_BINARY_DATA,

    1, 0, 0, 0,
    TEST_ENDPOINT_BINARY_DATA
  };

  ASSERT_EQ(expectedData, GetChannel().SerializedData);
  ASSERT_EQ(expectedData.size(), RawSize(response));
}

TEST_F(EndpointsDeserialization, GetEndpointsResponse)
{
  using namespace OpcUa;
  using namespace OpcUa::Binary;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xaf, 0x1, // TypeId
    // RequestHeader
    TEST_RESPONSE_HEADER_BINARY_DATA,

    1, 0, 0, 0,
    TEST_ENDPOINT_BINARY_DATA
  };

  GetChannel().SetData(expectedData);

  GetEndpointsResponse response;
  GetStream() >> response;

  ASSERT_EQ(response.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(response.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(response.TypeId.FourByteData.Identifier, OpcUa::GET_ENDPOINTS_RESPONSE);

  ASSERT_RESPONSE_HEADER_EQ(response.Header);

  ASSERT_EQ(response.Endpoints.size(), 1);
  ASSERT_ENDPOINT_EQ(response.Endpoints[0]);

  ASSERT_TRUE(Channel->IsEmpty());
}

const std::vector<unsigned char> GetEndpointsResponseRealData =
{
  0x4d, 0x53, 0x47, 0x46, 0xd2, 0x06, 0x00, 0x00, 0xfc, 0x4b, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,  // MSGF.....K......
  0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0xd8, 0xcd, 0x4e, 0x53,  // 4.............NS
  0x36, 0xda, 0xcd, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 6...............
  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e,  // ............opc.
  0x74, 0x63, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e,  // tcp://192.168.1.
  0x33, 0x36, 0x3a, 0x34, 0x39, 0x33, 0x32, 0x30, 0x34, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, 0x3a,  // 36:493204...urn:
  0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x3a,  // treww-a5855571b:
  0x4b, 0x65, 0x70, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65,  // Kepware.KEPServe
  0x72, 0x45, 0x58, 0x2e, 0x56, 0x35, 0x3a, 0x55, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,  // rEX.V5:UA Server
  0x34, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, 0x3a, 0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61, 0x35,  // 4...urn:treww-a5
  0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x3a, 0x4b, 0x65, 0x70, 0x77, 0x61, 0x72, 0x65, 0x2e,  // 855571b:Kepware.
  0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x58, 0x2e, 0x56, 0x35, 0x3a, 0x55,  // KEPServerEX.V5:U
  0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x03, 0x02, 0x00, 0x00, 0x00, 0x65, 0x6e, 0x1e,  // A Server.....en.
  0x00, 0x00, 0x00, 0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x58, 0x2f, 0x55,  // ...KEPServerEX/U
  0x41, 0x40, 0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31,  // A@treww-a5855571
  0x62, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00,  // b...............
  0x00, 0x1c, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, 0x74, 0x63, 0x70, 0x3a, 0x2f, 0x2f, 0x31,  // .....opc.tcp://1
  0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x33, 0x36, 0x3a, 0x34, 0x39, 0x33, 0x32,  // 92.168.1.36:4932
  0x30, 0xf3, 0x03, 0x00, 0x00, 0x30, 0x82, 0x03, 0xef, 0x30, 0x82, 0x03, 0x58, 0xa0, 0x03, 0x02,  // 0....0...0..X...
  0x01, 0x02, 0x02, 0x04, 0x84, 0x79, 0x20, 0xf2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,  // .....y .0...*.H.
  0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x60, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x0a, 0x09,  // .......0`1.0....
  0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x0f, 0x74, 0x72, 0x65, 0x77, 0x77,  // .&...,d....treww
  0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,  // -a5855571b1.0...
  0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,  // U....US1.0...U..
  0x13, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,  // ..Unknown1.0...U
  0x04, 0x03, 0x13, 0x15, 0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x58, 0x2f,  // ....KEPServerEX/
  0x55, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,  // UA Server0...121
  0x31, 0x30, 0x34, 0x30, 0x36, 0x33, 0x38, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,  // 104063845Z..2211
  0x30, 0x32, 0x30, 0x36, 0x33, 0x38, 0x34, 0x35, 0x5a, 0x30, 0x60, 0x31, 0x1f, 0x30, 0x1d, 0x06,  // 02063845Z0`1.0..
  0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x0f, 0x74, 0x72, 0x65,  // ...&...,d....tre
  0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x31, 0x0b, 0x30, 0x09,  // ww-a5855571b1.0.
  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,  // ..U....US1.0...U
  0x04, 0x0a, 0x13, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x31, 0x1e, 0x30, 0x1c, 0x06,  // ....Unknown1.0..
  0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45,  // .U....KEPServerE
  0x58, 0x2f, 0x55, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x30, 0x81, 0x9f, 0x30, 0x0d,  // X/UA Server0..0.
  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,  // ..*.H...........
  0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb0, 0x1f, 0x2b, 0xd7, 0x13, 0x46, 0x0d, 0xd6,  // .0........+..F..
  0x52, 0xa9, 0x94, 0x38, 0xef, 0x30, 0xc2, 0xe8, 0xcf, 0x2e, 0x72, 0x8c, 0x4d, 0x95, 0x66, 0xbf,  // R..8.0....r.M.f.
  0x0d, 0x55, 0xa3, 0x03, 0x24, 0xf1, 0xc2, 0x94, 0x1c, 0xf0, 0x72, 0x4c, 0x7b, 0x3f, 0xf0, 0x13,  // .U..$.....rL{?..
  0x26, 0x97, 0x25, 0xb0, 0x26, 0x30, 0x3f, 0xe7, 0xa9, 0x4b, 0xb7, 0xbf, 0x29, 0x5a, 0x14, 0x42,  // &.%.&0?..K..)Z.B
  0x20, 0xe6, 0xc0, 0x2e, 0x71, 0xb6, 0xb2, 0xb9, 0xb4, 0x56, 0x2c, 0x28, 0xb9, 0x5c, 0x87, 0xd5,  //  ...q....V,(.\..
  0xab, 0x26, 0x6d, 0x7c, 0x19, 0x3a, 0x51, 0x33, 0x04, 0x13, 0xf8, 0x79, 0x2c, 0x36, 0xae, 0xff,  // .&m|.:Q3...y,6..
  0xce, 0x76, 0x2b, 0x21, 0xfb, 0xdb, 0xef, 0xe4, 0x0a, 0xe1, 0x8a, 0x48, 0x3f, 0x58, 0xfe, 0xd7,  // .v+!.......H?X..
  0xa0, 0xea, 0x6d, 0x75, 0x57, 0xf4, 0x71, 0x0e, 0x91, 0xc5, 0x29, 0xb3, 0x91, 0x93, 0x9e, 0x27,  // ..muW.q...)....'
  0xfc, 0xe8, 0x36, 0x79, 0xd7, 0x96, 0xa1, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01,  // ..6y............
  0xb4, 0x30, 0x82, 0x01, 0xb0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,  // .0...0...U......
  0xcf, 0xfd, 0xaf, 0x08, 0x54, 0x3d, 0x74, 0x5a, 0xc8, 0x81, 0x4f, 0x80, 0xa0, 0x5e, 0xb8, 0xbe,  // ....T=tZ..O..^..
  0x16, 0x2d, 0x0f, 0xb1, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,  // .-..0...U.......
  0x03, 0x02, 0x02, 0xf4, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,  // ....0...U.......
  0x30, 0x00, 0x30, 0x81, 0x8d, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x85, 0x30, 0x81, 0x82,  // 0.0....U.#...0..
  0x80, 0x14, 0xcf, 0xfd, 0xaf, 0x08, 0x54, 0x3d, 0x74, 0x5a, 0xc8, 0x81, 0x4f, 0x80, 0xa0, 0x5e,  // ......T=tZ..O..^
  0xb8, 0xbe, 0x16, 0x2d, 0x0f, 0xb1, 0xa1, 0x64, 0xa4, 0x62, 0x30, 0x60, 0x31, 0x1f, 0x30, 0x1d,  // ...-...d.b0`1.0.
  0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x0f, 0x74, 0x72,  // ....&...,d....tr
  0x65, 0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x31, 0x0b, 0x30,  // eww-a5855571b1.0
  0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,  // ...U....US1.0...
  0x55, 0x04, 0x0a, 0x13, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x31, 0x1e, 0x30, 0x1c,  // U....Unknown1.0.
  0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x4b, 0x45, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,  // ..U....KEPServer
  0x45, 0x58, 0x2f, 0x55, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x82, 0x04, 0x84, 0x79,  // EX/UA Server...y
  0x20, 0xf2, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14,  //  .0 ..U.%.....0.
  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,  // ..+.........+...
  0x05, 0x07, 0x03, 0x02, 0x30, 0x6d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01,  // ....0m..`.H...B.
  0x0d, 0x04, 0x60, 0x16, 0x5e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62,  // ..`.^Generated b
  0x79, 0x20, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x40, 0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61,  // y SYSTEM@treww-a
  0x35, 0x38, 0x35, 0x35, 0x35, 0x37, 0x31, 0x62, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x32,  // 5855571b on 2012
  0x2d, 0x31, 0x31, 0x2d, 0x30, 0x34, 0x54, 0x30, 0x36, 0x3a, 0x33, 0x38, 0x3a, 0x34, 0x35, 0x2e,  // -11-04T06:38:45.
  0x32, 0x32, 0x39, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x53,  // 229 using OpenSS
  0x4c, 0x20, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x64, 0x20, 0x38, 0x20, 0x46, 0x65, 0x62, 0x20, 0x32,  // L 1.0.0d 8 Feb 2
  0x30, 0x31, 0x31, 0x30, 0x50, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x49, 0x30, 0x47, 0x86, 0x34,  // 0110P..U...I0G.4
  0x75, 0x72, 0x6e, 0x3a, 0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35, 0x35, 0x35,  // urn:treww-a58555
  0x37, 0x31, 0x62, 0x3a, 0x4b, 0x65, 0x70, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x4b, 0x45, 0x50, 0x53,  // 71b:Kepware.KEPS
  0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x58, 0x2e, 0x56, 0x35, 0x3a, 0x55, 0x41, 0x20, 0x53, 0x65,  // erverEX.V5:UA Se
  0x72, 0x76, 0x65, 0x72, 0x82, 0x0f, 0x74, 0x72, 0x65, 0x77, 0x77, 0x2d, 0x61, 0x35, 0x38, 0x35,  // rver..treww-a585
  0x35, 0x35, 0x37, 0x31, 0x62, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,  // 5571b0...*.H....
  0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x36, 0x3d, 0x98, 0xdc, 0xc8, 0xa2, 0x48, 0xfe,  // ........6=....H.
  0xbd, 0xc1, 0xdb, 0xf9, 0xfb, 0x32, 0x3b, 0x3d, 0x43, 0x6c, 0xff, 0xd3, 0x9d, 0xa0, 0x96, 0x80,  // .....2;=Cl......
  0x8a, 0x99, 0x0b, 0x19, 0x2b, 0x77, 0xd0, 0xd7, 0x66, 0x26, 0x45, 0xe4, 0x72, 0x5b, 0x7b, 0x62,  // ....+w..f&E.r[{b
  0xb6, 0x16, 0x25, 0x8c, 0xdf, 0x06, 0x53, 0x89, 0xb4, 0x19, 0x5d, 0xb3, 0x85, 0x50, 0x83, 0x86,  // ..%...S...]..P..
  0x1f, 0xc5, 0xa3, 0xc7, 0x8d, 0xd7, 0x0b, 0x0b, 0xfe, 0xd3, 0xb2, 0x54, 0x88, 0x9c, 0x41, 0xfd,  // ...........T..A.
  0x31, 0x83, 0x16, 0x49, 0x1e, 0x21, 0x16, 0xc5, 0x30, 0xaf, 0x72, 0xf2, 0x9b, 0x63, 0xe2, 0x96,  // 1..I.!..0.r..c..
  0x70, 0x97, 0x3c, 0x79, 0x4a, 0x58, 0x56, 0x9f, 0x2b, 0xa7, 0x66, 0x83, 0xd8, 0x43, 0xcf, 0x2b,  // p.<yJXV.+.f..C.+
  0xfe, 0x9b, 0x04, 0xa6, 0x8f, 0xa3, 0x23, 0x83, 0xff, 0x4f, 0xc7, 0x91, 0xa0, 0x9e, 0xfb, 0x5b,  // ......#..O.....[
  0x6c, 0xfe, 0xb7, 0x56, 0xee, 0x87, 0x1e, 0x89, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,  // l..V......../...
  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61,  // http://opcfounda
  0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x55, 0x41, 0x2f, 0x53, 0x65, 0x63, 0x75,  // tion.org/UA/Secu
  0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x23, 0x4e, 0x6f, 0x6e, 0x65, 0x02,  // rityPolicy#None.
  0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73,  // .......Anonymous
  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // ................
  0x08, 0x00, 0x00, 0x00, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x01, 0x00, 0x00, 0x00,  // ....UserName....
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x38, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70,  // ........8...http
  0x3a, 0x2f, 0x2f, 0x6f, 0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,  // ://opcfoundation
  0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x55, 0x41, 0x2f, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,  // .org/UA/Security
  0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x23, 0x42, 0x61, 0x73, 0x69, 0x63, 0x31, 0x32, 0x38, 0x52,  // Policy#Basic128R
  0x73, 0x61, 0x31, 0x35, 0x41, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f,  // sa15A...http://o
  0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f, 0x72, 0x67,  // pcfoundation.org
  0x2f, 0x55, 0x41, 0x2d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2f, 0x54, 0x72, 0x61, 0x6e,  // /UA-Profile/Tran
  0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x61, 0x74, 0x63, 0x70, 0x2d, 0x75, 0x61, 0x73, 0x63,  // sport/uatcp-uasc
  0x2d, 0x75, 0x61, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // -uabinary.......
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,  // ................
  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,  // ................
  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,  // ................
  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,  // ................
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,  // ................
  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,  // ................
  0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // ................
  0xff, 0x00
};                                                                       //  ..

TEST_F(EndpointsDeserialization, GetEndpointsResponseReal)
{
  using namespace OpcUa;
  using namespace OpcUa::Binary;

  GetChannel().SetData(std::vector<char>(GetEndpointsResponseRealData.begin(), GetEndpointsResponseRealData.end()));

  SecureHeader responseHeader;
  GetStream() >> responseHeader;

  SymmetricAlgorithmHeader responseAlgo;
  GetStream() >> responseAlgo;

  SequenceHeader responseSequence;
  GetStream() >> responseSequence; // TODO Check for request Number

  GetEndpointsResponse response;
  GetStream() >> response;

  ASSERT_EQ(response.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(response.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(response.TypeId.FourByteData.Identifier, OpcUa::GET_ENDPOINTS_RESPONSE);

  ASSERT_EQ(response.Endpoints.size(), 5);

  ASSERT_TRUE(Channel->IsEmpty());
}


//-------------------------------------------------------
// FindServersParameters
//-------------------------------------------------------

TEST_F(EndpointsSerialization, FindServersParameters)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  FindServersParameters params;

  params.EndpointUrl = "url";
  params.Locales.push_back("en");
  params.ServersToReturn.push_back("server");

  GetStream() << params << flush;

  const std::vector<char> expectedData =
  {
    3, 0, 0, 0, 'u', 'r', 'l',
    1, 0, 0, 0, 2, 0, 0, 0, 'e', 'n',
    1, 0, 0, 0, 6, 0, 0, 0, 's', 'e', 'r', 'v', 'e', 'r'
  };

  ASSERT_EQ(expectedData, GetChannel().SerializedData);
  ASSERT_EQ(expectedData.size(), RawSize(params));
}

TEST_F(EndpointsDeserialization, FindServersParameters)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  const std::vector<char> expectedData =
  {
    3, 0, 0, 0, 'u', 'r', 'l',
    1, 0, 0, 0, 2, 0, 0, 0, 'e', 'n',
    1, 0, 0, 0, 6, 0, 0, 0, 's', 'e', 'r', 'v', 'e', 'r'
  };

  GetChannel().SetData(expectedData);

  FindServersParameters params;
  GetStream() >> params;

  ASSERT_EQ(params.EndpointUrl, "url");
  ASSERT_EQ(params.Locales.size(), 1);
  ASSERT_EQ(params.Locales[0], "en");
  ASSERT_EQ(params.ServersToReturn.size(), 1);
  ASSERT_EQ(params.ServersToReturn[0], "server");
}

//-------------------------------------------------------
// FindServersRequest
//-------------------------------------------------------

TEST_F(EndpointsSerialization, FindServersRequest)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  FindServersRequest request;

  ASSERT_EQ(request.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(request.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(request.TypeId.FourByteData.Identifier, OpcUa::FIND_ServerS_REQUEST);

  FILL_TEST_REQUEST_HEADER(request.Header);
  request.Parameters.EndpointUrl = "url";
  request.Parameters.Locales.push_back("en");
  request.Parameters.ServersToReturn.push_back("server");


  GetStream() << request << flush;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xa6, 0x1, // TypeId
    // RequestHeader
    TEST_REQUEST_HEADER_BINARY_DATA,
    3, 0, 0, 0, 'u', 'r', 'l',
    1, 0, 0, 0, 2, 0, 0, 0, 'e', 'n',
    1, 0, 0, 0, 6, 0, 0, 0, 's', 'e', 'r', 'v', 'e', 'r'
  };

  ASSERT_EQ(expectedData, GetChannel().SerializedData);
  ASSERT_EQ(expectedData.size(), RawSize(request));
}

TEST_F(EndpointsDeserialization, FindServersRequest)
{
  using namespace OpcUa;
  using namespace OpcUa::Binary;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xa6, 0x1, // TypeId
    // RequestHeader
    TEST_REQUEST_HEADER_BINARY_DATA,
    3, 0, 0, 0, 'u', 'r', 'l',
    1, 0, 0, 0, 2, 0, 0, 0, 'e', 'n',
    1, 0, 0, 0, 6, 0, 0, 0, 's', 'e', 'r', 'v', 'e', 'r'
  };

  GetChannel().SetData(expectedData);

  FindServersRequest request;
  GetStream() >> request;

  ASSERT_EQ(request.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(request.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(request.TypeId.FourByteData.Identifier, OpcUa::FIND_ServerS_REQUEST);

  ASSERT_REQUEST_HEADER_EQ(request.Header);

  ASSERT_EQ(request.Parameters.EndpointUrl, "url");
  ASSERT_EQ(request.Parameters.Locales, std::vector<std::string>(1, "en"));
  ASSERT_EQ(request.Parameters.ServersToReturn, std::vector<std::string>(1, "server"));
}

//----------------------------------------------------
// FindServersResponse
//----------------------------------------------------

TEST_F(EndpointsSerialization, FindServersResponse)
{

  using namespace OpcUa;
  using namespace OpcUa::Binary;

  FindServersResponse response;

  ASSERT_EQ(response.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(response.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(response.TypeId.FourByteData.Identifier, OpcUa::FIND_ServerS_RESPONSE);

  FILL_TEST_RESPONSE_HEADER(response.Header);

  ApplicationDescription desc;
  FILL_APPLICATION_DESCRIPTION(desc);
  response.Data.Descriptions.push_back(desc);

  GetStream() << response << flush;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xa9, 0x1, // TypeId
    // RequestHeader
    TEST_RESPONSE_HEADER_BINARY_DATA,

    1, 0, 0, 0,
    TEST_APPLICATION_DESCRIPTION_BINARY_DATA
  };

  ASSERT_EQ(expectedData, GetChannel().SerializedData);
  ASSERT_EQ(expectedData.size(), RawSize(response));
}

TEST_F(EndpointsDeserialization, FindServersResponse)
{
  using namespace OpcUa;
  using namespace OpcUa::Binary;

  const std::vector<char> expectedData =
  {
    1, 0, (char)0xa9, 0x1, // TypeId
    // RequestHeader
    TEST_RESPONSE_HEADER_BINARY_DATA,

    1, 0, 0, 0,
    TEST_APPLICATION_DESCRIPTION_BINARY_DATA
  };

  GetChannel().SetData(expectedData);

  FindServersResponse response;
  GetStream() >> response;

  ASSERT_EQ(response.TypeId.Encoding, EV_FOUR_BYTE);
  ASSERT_EQ(response.TypeId.FourByteData.NamespaceIndex, 0);
  ASSERT_EQ(response.TypeId.FourByteData.Identifier, OpcUa::FIND_ServerS_RESPONSE);

  ASSERT_RESPONSE_HEADER_EQ(response.Header);

  ASSERT_EQ(response.Data.Descriptions.size(), 1);
  ASSERT_APPLICATION_DESCRIPTION_EQ(response.Data.Descriptions[0]);

  ASSERT_TRUE(Channel->IsEmpty());
}
